import React, { useEffect, useState } from 'react';
import { NetworkStatus } from '@apollo/client';
import {
  Box,
  Datepicker,
  GridCarousel,
  GridItem,
  Icon,
  ListBase,
  MainColorType,
  makeToast,
  NotificationBanner,
  Text,
} from '@nova-hf/ui';
import { ErrorBanner } from 'beta/components/error/ErrorBanner';
import Authentication from 'beta/store/authentication';
import { formatDate } from 'beta/utils/helpers';
import { inject } from 'mobx-react';
import { useRouter } from 'next/router';
import {
  FiberOrderStatus,
  FiberProvider,
  ServiceStatus,
  useActivateServiceMutation,
  useFiberOrderActivationTimeQuery,
  useFiberOrderQuery,
  useServiceStatusQuery,
  useUpdateFiberOrderActivationDateMutation,
} from 'typings/graphql';
import { useTranslation } from 'utils/i18n';

export type SelectHours = {
  label: string;
  value: number;
};

type FiberServiceActivateProps = {
  fiberOrderId: string;
  serviceId: string;
  serviceOssId: string;
  color: MainColorType;
  shouldRefetchServiceIfActivated: () => void;
  authentication?: Authentication;
};

const FiberServiceActivate = ({
  fiberOrderId,
  serviceOssId,
  color,
  shouldRefetchServiceIfActivated,
  authentication,
}: FiberServiceActivateProps) => {
  const { t } = useTranslation(['fiber', 'errors', 'service']);
  const router = useRouter();
  const serviceId = typeof router?.query?.serviceId === 'string' ? router?.query?.serviceId : '';
  const customerId = typeof router?.query?.customerId === 'string' ? router?.query?.customerId : '';

  const [isChangingActivateDate, setIsChangingActivateDate] = useState<boolean>(false);
  const [activateDate, setActivateDate] = useState<Date | undefined>(undefined);
  const [selectedDateAndHours, setSelectedDateAndHours] = useState<Date | null>(null);
  const [selectableDateAndHours, setSelectableDateAndHourse] = useState<(Date | null)[]>([]);
  const [currentActivateDate, setCurrentActivateDate] = useState<string>();
  const [currentActivateTime, setCurrentActivateTime] = useState<string>();
  const [errorMessage, setErrorMessage] = useState('');

  const isStaff = authentication?.isStaff;

  const monthNames = [
    t('service:months.january'),
    t('service:months.february'),
    t('service:months.march'),
    t('service:months.april'),
    t('service:months.may'),
    t('service:months.june'),
    t('service:months.july'),
    t('service:months.august'),
    t('service:months.september'),
    t('service:months.october'),
    t('service:months.november'),
    t('service:months.december'),
  ];

  const { data: serviceData } = useServiceStatusQuery({
    variables: {
      serviceId,
    },
    skip: !serviceId || !customerId,
  });

  const isTengir =
    serviceData?.service?.__typename === 'FiberService' &&
    serviceData.service.provider === FiberProvider.Tengir;
  const isMila =
    serviceData?.service?.__typename === 'FiberService' &&
    serviceData.service.provider === FiberProvider.Mila;

  const {
    data: fiberOrderData,
    loading: fiberOrderLoading,
    error: fiberOrderError,
    refetch: fiberOrderRefetch,
    networkStatus: fiberOrderNetworkStatus,
  } = useFiberOrderQuery({
    variables: {
      input: {
        fiberOrderId: fiberOrderId ?? '',
      },
    },
    fetchPolicy: 'network-only',
  });

  const fiberOrder = fiberOrderData?.fiberOrder;
  const fiberOrderNeedsToActivate =
    serviceData?.service.status === ServiceStatus.Pending && !fiberOrder?.needsVisit;
  const toBeOrdered = fiberOrder?.status === FiberOrderStatus.ToBeOrdered;

  const orderActivationDate = fiberOrder?.activationDate
    ? new Date(fiberOrder?.activationDate)
    : undefined;

  const customerCanActivateNow =
    fiberOrder?.status === FiberOrderStatus.Completed && serviceOssId !== null;
  const activationDateHasPassed = orderActivationDate
    ? new Date(orderActivationDate) < new Date()
    : false;

  const [updateActivateDate, { loading: updateActivateDateLoading }] =
    useUpdateFiberOrderActivationDateMutation({
      onCompleted() {
        fiberOrderRefetch();
        setIsChangingActivateDate(!isChangingActivateDate);
        makeToast.success(t('fiber:fiberActivate.activateDateText'), '');
      },
      onError(error) {
        if (error instanceof Error)
          makeToast.danger(t('fiber:fiberActivate.failText'), error.message);
        setErrorMessage(error.message);
      },
    });

  const [activateFiberService, { loading: activateFiberLoading }] = useActivateServiceMutation({
    onCompleted() {
      shouldRefetchServiceIfActivated();
      makeToast.success(t('fiber:fiberActivate.activateText'), '');
    },
    onError(error) {
      if (error instanceof Error)
        makeToast.danger(t('fiber:fiberActivate.failText'), error.message);
      setErrorMessage(error.message);
    },
  });

  const handleActivateFiberNow = async () => {
    await activateFiberService({
      variables: {
        input: {
          id: serviceId ?? '',
        },
      },
    });
  };

  const handleSetActivateDate = async () => {
    if ((selectedDateAndHours || !isLjosleidarinn) && activateDate) {
      const setActivateDate =
        (isLjosleidarinn && selectedDateAndHours) || (isMila && selectedDateAndHours)
          ? selectedDateAndHours
          : activateDate;
      await updateActivateDate({
        variables: {
          input: {
            fiberOrderId: fiberOrderId,
            activationDate: setActivateDate,
          },
        },
      });
    }
  };

  const provider = fiberOrder?.provider ? (fiberOrder?.provider as FiberProvider) : undefined;
  const {
    data: activationDateData,
    loading: activationDateLoading,
    error: activationDateError,
    refetch: activationDateRefetch,
    networkStatus: activationDateNetworkStatus,
  } = useFiberOrderActivationTimeQuery({
    skip: !provider,
    variables: {
      input: {
        fiberProvider: provider,
      },
    },
  });

  const isLjosleidarinn = provider === FiberProvider.Ljosleidarinn;
  const activationDate =
    !activationDateHasPassed && orderActivationDate
      ? orderActivationDate
      : activationDateData?.fiberOrderActivationTimes?.length
      ? new Date(activationDateData?.fiberOrderActivationTimes[0] as unknown as string)
      : new Date();

  useEffect(() => {
    if (activationDateData?.fiberOrderActivationTimes) {
      setActivateDate(activationDate);
    }
  }, [activationDateData?.fiberOrderActivationTimes]);

  useEffect(() => {
    if (activationDateData?.fiberOrderActivationTimes?.length && activateDate) {
      const filteredOutHours = activationDateData.fiberOrderActivationTimes.filter((date) => {
        const cleanDate = new Date(date as string).setHours(0, 0, 0, 0);
        const cleanSelectedDate = activateDate?.setHours(0, 0, 0, 0);
        return cleanDate === cleanSelectedDate;
      });
      setSelectableDateAndHourse(filteredOutHours);
    }
  }, [activateDate]);

  const sixtyDaysFromNow = new Date();
  sixtyDaysFromNow.setDate(sixtyDaysFromNow.getDate() + 60);

  const fetchLastAvailableDate = (): Date => {
    const activationTimes = activationDateData?.fiberOrderActivationTimes;
    const length = activationTimes?.length;
    if (length) {
      return new Date(activationTimes[length - 1] as unknown as string);
    }
    return sixtyDaysFromNow;
  };

  useEffect(() => {
    if (orderActivationDate) {
      setCurrentActivateDate(
        `${formatDate(orderActivationDate, 'dd')}.${monthNames[orderActivationDate.getMonth()]}`,
      );
      setCurrentActivateTime(formatDate(orderActivationDate, 'HH:mm'));
    }
  }, [orderActivationDate]);

  if (!fiberOrderNeedsToActivate && !toBeOrdered) return null;
  if (
    fiberOrderLoading ||
    fiberOrderError ||
    !fiberOrderData ||
    !activationDateData?.fiberOrderActivationTimes?.length ||
    activationDateError ||
    activationDateLoading
  ) {
    return (
      <>
        <ErrorBanner
          eyebrowTexts={[
            t('errors:contractList.netid.eyebrows.1'),
            t('errors:contractList.netid.eyebrows.2'),
            t('errors:contractList.netid.eyebrows.3'),
          ]}
          titles={[
            t('errors:contractList.netid.titles.1'),
            t('errors:contractList.netid.titles.2'),
            t('errors:contractList.netid.titles.3'),
          ]}
          descriptions={[
            t('errors:contractList.netid.descriptions.1'),
            t('errors:contractList.netid.descriptions.2'),
            t('errors:contractList.netid.descriptions.3'),
          ]}
          icon="zap"
          color={color}
          showLoading={
            fiberOrderLoading ||
            activationDateLoading ||
            fiberOrderNetworkStatus === NetworkStatus.refetch ||
            activationDateLoading ||
            activationDateNetworkStatus === NetworkStatus.refetch
          }
          refetchButton={{
            text: t('errors:buttons.refresh'),
            icon: 'refresh',
            onClick: async () => {
              if (!fiberOrderData?.fiberOrder) await fiberOrderRefetch();
              if (!activationDateData?.fiberOrderActivationTimes?.length && fiberOrder)
                await activationDateRefetch({
                  input: {
                    fiberProvider: fiberOrder.provider as FiberProvider,
                  },
                });
            },
          }}
          loadingComponent={
            <>
              <ListBase isLoading gap={3} />
              <ListBase isLoading gap={3} />
              <ListBase isLoading />
            </>
          }
        />
      </>
    );
  }

  if (toBeOrdered) {
    return (
      <>
        <NotificationBanner
          description={t('fiber:toBeOrdered.description')}
          eyebrowText={t('fiber:toBeOrdered.eyebrow')}
          icon="warning"
          title={t('fiber:toBeOrdered.title')}
          color="warning"
        />
      </>
    );
  }

  const minDate =
    !isLjosleidarinn && activationDateData?.fiberOrderActivationTimes.length
      ? new Date(activationDateData?.fiberOrderActivationTimes[0] as unknown as string)
      : new Date();

  return (
    <NotificationBanner
      icon={'home'}
      eyebrowText={t('fiber:fiberActivate.eyebrow')}
      title={t('fiber:fiberActivate.title')}
      hasPingAlert
      color={color}
      description={
        activationDateHasPassed
          ? t('fiber:fiberActivate.activationSystemFailText')
          : isLjosleidarinn || isMila
          ? t('fiber:fiberActivate.ljosLeidarinnDescription', {
              activateDate: currentActivateDate,
              activateTime: currentActivateTime,
            })
          : t('fiber:fiberActivate.tengirDescription', {
              activateDate: currentActivateDate,
            })
      }
      {...(!isTengir && {
        mainButtonWhite: {
          text: t('fiber:fiberActivate.chooseActivateButton'),
          icon: 'calendar',
          onClick: () => setIsChangingActivateDate(!isChangingActivateDate),
        },
      })}
      {...(customerCanActivateNow && {
        mainButtonColored: {
          text: t('fiber:fiberActivate.activateNowButton'),
          icon: 'longArrowRight',
          onClick: () => handleActivateFiberNow(),
          isLoading: activateFiberLoading,
        },
      })}
      {...(isChangingActivateDate && {
        mainButtonColored: {
          text: t('fiber:fiberActivate.confirmButton'),
          icon: 'checkBox',
          onClick: async () => {
            await handleSetActivateDate();
          },
          isLoading: updateActivateDateLoading,
          isDisabled: updateActivateDateLoading,
        },
        mainButtonWhite: {
          text: t('fiber:fiberActivate.cancelButton'),
          icon: 'close',
          onClick: () => setIsChangingActivateDate(!isChangingActivateDate),
        },
      })}
    >
      {isChangingActivateDate && (
        <>
          <Datepicker
            selected={activateDate || activationDate}
            onSelect={(date) => setActivateDate(date)}
            inputId={'activateDate'}
            inputName={'activateDate'}
            color={color}
            minDate={minDate}
            maxDate={isTengir ? fetchLastAvailableDate() : sixtyDaysFromNow}
            {...(isTengir && {
              includedDates: activationDateData?.fiberOrderActivationTimes,
              filterDate: (date: Date) => {
                const day = date.getDay();
                return day !== 0 && day !== 6;
              },
            })}
          />
          {(isMila || isLjosleidarinn) && (
            <>
              <Text variant="subtitleBold" marginTop={5} marginBottom={3}>
                {t('fiber:fiberActivate.selectTime')}
              </Text>
              <GridCarousel
                color={color}
                numberOnSlide={16}
                gridTemplate={{ sm: 4, md: 6, xl: 10 }}
                gridGap={{ sm: 2, lg: 3 }}
                backButtonHiddenTitle={t('fiber:fiberActivate.previousPage')}
                nextButtonHiddenTitle={t('fiber:fiberActivate.nextPage')}
              >
                {selectableDateAndHours.map((allowedTime, i) => {
                  const newDate = new Date(allowedTime);
                  const hourTime =
                    newDate.getHours().toString().padStart(2, '0') +
                    ':' +
                    newDate.getMinutes().toString().padStart(2, '0');
                  return (
                    <GridItem key={i} gridColumn={{ sm: 'span2' }}>
                      <Box
                        renderAs="button"
                        width="100%"
                        display="flex"
                        justifyContent="space-around"
                        alignItems="center"
                        paddingX={3}
                        paddingY={4}
                        borderColor={{
                          hover: color,
                          focusVisible: color,
                          sm: selectedDateAndHours === allowedTime ? color : 'grey200',
                        }}
                        borderStyle="solid"
                        borderWidth="2px"
                        onClick={() => setSelectedDateAndHours(allowedTime)}
                        dottedShadow={{ sm: 'none', md: 'small' }}
                        backgroundColor="white"
                      >
                        <Icon icon="history" color={color} />
                        <Text variant="pLargeBold">{hourTime}</Text>
                      </Box>
                    </GridItem>
                  );
                })}
              </GridCarousel>
            </>
          )}
          {errorMessage && (
            <Text variant="subtitleBold" color="warning" marginTop={2} marginBottom={2}>
              {isStaff ? errorMessage : t('fiber:fiberActivate.activationFailFallback')}
            </Text>
          )}
        </>
      )}
    </NotificationBanner>
  );
};
export default inject('authentication')(FiberServiceActivate);
